/**
 * 
 */
package gui;

import utility.*;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.JOptionPane;
import javax.swing.tree.*;

import utility.SymbolEntry;
import utility.SymbolTable;

import java.util.Stack;

/**
 * @author xxbidiao
 * 
 */
public class AssemblyGenerator {

	public class AssemblySTNode {
		// the name of the valuable.
		public String name;

		// the type of the variable. only base type.
		public String type;

		// the size of the valuable.
		public int arrayIndex;

		// where the vector is in.
		public String scope;

		// the times this value gets value. For IR making
		public int tmpV = 0;

		// Represent if it is a parameter.
		public boolean isParam = false;
	}

	public Vector<AssemblySTNode> SymbolList = new Vector<AssemblySTNode>();

	public Vector<AssemblySTNode> SL_Global = new Vector<AssemblySTNode>();

	public Vector<AssemblySTNode> SL_inFunc = new Vector<AssemblySTNode>();

	public Vector<String> functionNameList = new Vector<String>();

	public Vector<AssemblySTNode> getSymbolsInScope(String theScope) {
		Vector<AssemblySTNode> ST = new Vector<AssemblySTNode>();
		for (int i = 0; i < SymbolList.size(); i++) {
			if (theScope.equals((SymbolList.get(i)).scope)) {
				ST.add(SymbolList.get(i));
			}
		}
		return ST;
	}

	// save current type in expression.
	public String currentTypeInExpression = "int";

	public void getSymbolList() throws ParseException {
		/*
		 * GlowwormDumpVisitor gdv = new GlowwormDumpVisitor(); Object data =
		 * null; SimpleNode n = inputNode; n.jjtAccept(gdv, data); SymbolTable
		 * ST = gdv.getSymTable();
		 */
		SymbolTable ST = MainFrame.st;
		int depth = 0;
		int maxDepth = ST.getDepth() + 1;
		ArrayList allSymbol = ST.getScopeDisplay();
		for (int currentDepth = 0; currentDepth < maxDepth; currentDepth++) {
			SymbolEntry theSE = (SymbolEntry) allSymbol.get(currentDepth);

			// build function-name array
			while (theSE != null) {
				if (!(theSE.getAttributes().getKind().equals("func"))) {
					theSE = theSE.getLevel();
					continue;
				}
				int theLV = theSE.getDepth();
				String name = theSE.getName();
				functionNameList.add(name);
				theSE = theSE.getLevel();
			}
		}
		Stack<String> reversing = new Stack<String>();
		for (int i = 0; i < functionNameList.size(); i++) {
			reversing.push(functionNameList.get(i));
		}
		functionNameList.clear();
		functionNameList.add("__Global");
		while (!reversing.empty()) {
			functionNameList.add(reversing.pop());
		}
		// end
		for (int currentDepth = 0; currentDepth < maxDepth; currentDepth++) {
			SymbolEntry theSE = (SymbolEntry) allSymbol.get(currentDepth);
			while (theSE != null) {
				if (!theSE.getAttributes().getKind().equals("var")) {
					theSE = theSE.getLevel();
					continue;
				}
				AssemblySTNode theSTNode = new AssemblySTNode();
				theSTNode.name = theSE.getName();
				theSTNode.type = theSE.getAttributes().getType();
				if (theSTNode.type.equals("array")) {
					theSTNode.arrayIndex = ((ArrayAttributes) theSE
							.getAttributes()).getBounds();
					theSTNode.type = ((ArrayAttributes) theSE.getAttributes())
							.getEleType();
				} else {
					theSTNode.arrayIndex = 0;
				}
				theSTNode.scope = functionNameList.get(theSE.getDepth());
				theSTNode.isParam = theSE.getAttributes().getParameter();
				SymbolList.add(theSTNode);
				theSE = theSE.getLevel();
			}
		}
		SL_Global = getSymbolsInScope("__Global");

	}

	// holds stack of used variables. For expression generation
	public Stack<String> values = new Stack<String>();

	public Stack<String> ops = new Stack<String>();

	String getType(String s) {
		int colonPosition = s.indexOf(":");
		if (colonPosition != -1) {
			s = s.substring(0, colonPosition);
			s = s.replaceAll(" ", "");
		}
		return s;
	}

	String getCode(String s) {
		int colonPosition = s.indexOf(":");
		if (colonPosition != -1) {
			String result = s.substring(colonPosition + 1, s.length());
			return result.replaceAll("^[ ]+", "");
		} else {
			return "";
		}
	}

	int hasChildrenWithType(DefaultMutableTreeNode node, String type) {
		for (int i = 0; i < node.getChildCount(); i++) {
			String thisString = node.getChildAt(i).toString();
			String thisType = getType(thisString);
			if (thisType.equals(type) || ("_" + thisType).equals(type)) {
				return i;
			}
		}
		return -1;
	}

	public AssemblyGenerator() {

		/*
		 * //test stub AssemblySTNode e = new AssemblySTNode(); e.name = "i";
		 * e.scope = "__Global"; e.type = "int"; SL_Global.add(e);
		 * AssemblySTNode f = new AssemblySTNode(); f.name = "j"; f.scope =
		 * "__Global"; f.type = "int"; SL_Global.add(f); AssemblySTNode g = new
		 * AssemblySTNode(); g.name = "k"; g.scope = "__Global"; g.type = "int";
		 * SL_Global.add(g);
		 */
		try {
			getSymbolList();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

	public DefaultMutableTreeNode root;

	public String result = "";

	public boolean isInFunction = false;

	public String currentScope;

	public boolean passedMain = false;

	public int currentBranchNum = 0;

	public String getBranchNum() {
		currentBranchNum++;
		return "%" + currentBranchNum;
	}

	public int currentTmpNum = 0;

	public String getTmpVal() {
		currentTmpNum++;
		return tValPrefix + currentTmpNum;
	}

	String tValPrefix = "%__";

	// get whether the ID is a global or only scope in function.
	public String getValueRep(String ID) {
		if (isInFunction) {
			// in function, maybe it is % not @.
			for (int i = 0; i < SL_inFunc.size(); i++) {
				String nameInList = SL_inFunc.get(i).name;
				if (SL_inFunc.get(i).name.equals(ID)) {
					return "%" + ID;
				}
			}
			for (int i = 0; i < SL_Global.size(); i++) {
				String nameInList = SL_Global.get(i).name;
				if (SL_Global.get(i).name.equals(ID)) {
					return "@" + ID;
				}
			}
		} else {
			for (int i = 0; i < SL_Global.size(); i++) {
				String nameInList = SL_Global.get(i).name;
				if (SL_Global.get(i).name.equals(ID)) {
					return "@" + ID;
				}
			}
		}
		// error("Unknown symbol [" + ID + "]");
		return "%" + ID;

	}

	public String functionReturn = "";

	public void codeGen(DefaultMutableTreeNode node) {

		// all rulesets.
		String nodeType = getType(node.toString());
		String nodeCode = getCode(node.toString());
		if (nodeType.equals("program")) {
			// output all global assignments here
			for (int i = 0; i < SL_Global.size(); i++) {
				String IDName = SL_Global.get(i).name;
				String IDType = SL_Global.get(i).type;
				if (SL_Global.get(i).arrayIndex != 0) {
					result += _global(IDName, IDType,
							SL_Global.get(i).arrayIndex);
				} else
					result += _global(IDName, IDType);
			}
			for (int i = 0; i < node.getChildCount(); i++) {
				codeGen((DefaultMutableTreeNode) node.getChildAt(i));
			}
		} else if (nodeType.equals("functionImpl")) {
			isInFunction = true;
			for (int nodeCount = 0; nodeCount < node.getChildCount(); nodeCount++) {
				DefaultMutableTreeNode theNode = (DefaultMutableTreeNode) node
						.getChildAt(nodeCount);
				if (getType(theNode.toString()).equals("functionHead")) {
					DefaultMutableTreeNode fHead = theNode;
					int idLoc = hasChildrenWithType(fHead, "id");
					DefaultMutableTreeNode ID = ((DefaultMutableTreeNode) fHead
							.getChildAt(idLoc));
					String functionName = getCode(ID.toString());
					currentScope = functionName;
					SL_inFunc = getSymbolsInScope(currentScope);
					// get all function arguments
					String functionArgList = "";
					boolean isFirstParam = true;
					for (int i = 0; i < SL_inFunc.size(); i++) {
						// result += _alloca(getValueRep(SL_inFunc.get(i).name),
						// SL_inFunc.get(i).type);
						String IDName = SL_inFunc.get(i).name;
						String IDType = SL_inFunc.get(i).type;
						if (!SL_inFunc.get(i).isParam)
							continue;
						if (SL_inFunc.get(i).arrayIndex != 0) {
							// result += _alloca(getValueRep(IDName), IDType,
							// SL_inFunc.get(i).arrayIndex);
							// --not supported--
						} else {
							if (isFirstParam) {
								isFirstParam = false;
							} else {
								functionArgList += " , ";
							}
							functionArgList += typeInLLVM(SL_inFunc.get(i).type)
									+ " " + getValueRep(IDName) + "__";

						}
					}
					// end
					result += "define i32 @" + functionName + "("
							+ functionArgList + ") nounwind uwtable {\n";

					// transport in arguments
					// define local variables

					// for grammar issue, give a trick
					for (int i = 0; i < SL_inFunc.size(); i++) {
						// result += _alloca(getValueRep(SL_inFunc.get(i).name),
						// SL_inFunc.get(i).type);
						String IDName = SL_inFunc.get(i).name;
						String IDType = SL_inFunc.get(i).type;
						if (SL_inFunc.get(i).isParam) {
							result += _alloca(getValueRep(IDName), IDType);
							result += _store(getValueRep(IDName) + "__",
									getValueRep(IDName), IDType);
						} else {
							if (SL_inFunc.get(i).arrayIndex != 0) {
								result += _alloca(getValueRep(IDName), IDType,
										SL_inFunc.get(i).arrayIndex);
							} else {
								result += _alloca(getValueRep(IDName), IDType);
							}
						}

					}
				} else if (getType(theNode.toString()).equals("block")) {
					// main code.
					// int fBlockLoc = hasChildrenWithType(node, "block");
					// DefaultMutableTreeNode fBlock = (DefaultMutableTreeNode)
					// node
					// .getChildAt(fBlockLoc);
					codeGen(theNode);

				} else if (getType(theNode.toString()).equals("return_")) {
					String retTmp = getTmpVal();
					int retIDLoc = hasChildrenWithType(theNode, "id");
					String retID = getCode(theNode.getChildAt(retIDLoc)
							.toString());
					result += _load(getValueRep(retID), retTmp, "int");
					String returning = retTmp;
					result += "ret i32 " + returning + " \n }\n";
					currentBranchNum = 0;
					currentBranchNum = 0;
				}
			}
			currentScope = "__Global";
			isInFunction = false;

		} else if (nodeType.equals("block")) {
			if (isInFunction) {
				for (int i = 0; i < node.getChildCount(); i++)
					codeGen((DefaultMutableTreeNode) node.getChildAt(i));
			} else if (!isInFunction && !passedMain) // the global main
														// function.
			{
				currentScope = "__Global";
				// the main thing is only outputed once!
				passedMain = true;
				result += "define i32 @main() nounwind uwtable {\n";
				for (int i = 0; i < node.getChildCount(); i++)
					codeGen((DefaultMutableTreeNode) node.getChildAt(i));
				result += "ret i32 0 \n}\n";
			} else {
				for (int i = 0; i < node.getChildCount(); i++)
					codeGen((DefaultMutableTreeNode) node.getChildAt(i));
			}
		} else if (nodeType.equals("functionCall")) {
			int idLoc = hasChildrenWithType(node, "id");
			String functionName = getCode(node.getChildAt(idLoc).toString());
			String retVal = getTmpVal();
			DefaultMutableTreeNode considerNode = node;
			if (considerNode.getChildCount() == 1) {
				considerNode = (DefaultMutableTreeNode) node.getChildAt(0);
			}
			int alLoc = 0;
			alLoc = hasChildrenWithType(considerNode, "argList");
			considerNode = (DefaultMutableTreeNode) considerNode
					.getChildAt(alLoc);
			for (int i = 0; i < considerNode.getChildCount(); i++)
				codeGen((DefaultMutableTreeNode) considerNode.getChildAt(i));
			result += retVal + " = call i32 @" + functionName + "(";
			Stack<String> temp = new Stack<String>();
			while (!values.empty()) {
				temp.push(values.pop());
			}
			while (!temp.empty()) {
				result += "i32 " + temp.pop();
				if (!temp.empty())
					result += " , ";
			}
			result += ")\n";
			functionReturn = retVal;

		} else if (nodeType.equals("assign")) {
			// first find ID.
			int idLoc = hasChildrenWithType(node, "id");
			if (idLoc == -1)
				error("No lhs in assign");
			String nameOfID = getCode(node.getChildAt(idLoc).toString());
			DefaultMutableTreeNode theIDNode = (DefaultMutableTreeNode) node
					.getChildAt(idLoc);
			DefaultMutableTreeNode considerNode;
			if (theIDNode.getChildCount() > 0) {
				// it's a bug. I have to fix it
				considerNode = theIDNode;
			} else {
				considerNode = node;
			}
			boolean funcCallDeal = false;
			int funCallLoc = hasChildrenWithType(considerNode, "functionCall");
			if (funCallLoc != -1) {
				codeGenAssignWithFunc(node);
				funcCallDeal = true;
			}

			if (!funcCallDeal) {
				int expLoc = hasChildrenWithType(considerNode, "expression");
				// if (expLoc == -1)
				// error("No rhs in assign");

				codeGen((DefaultMutableTreeNode) considerNode
						.getChildAt(expLoc));
				boolean deal = false;
				for (int i = 0; i < considerNode.getChildCount(); i++) {
					String theStr = considerNode.getChildAt(i).toString();
					String theType = getType(theStr);
					String theCode = getCode(theStr);
					if (theType.equals("id") && !nameOfID.equals(theCode)) {
						// variable index

						String nextIDCode = theCode;
						// start operation
						String tmp1 = getTmpVal();
						result += _load(getValueRep(nextIDCode), tmp1, "int");
						String tmp2 = getTmpVal();
						result += tmp2 + " = sext i32 " + tmp1 + " to i64\n";
						int ttt = 1;
						// String theTmp = getTmpVal();
						String IDNameraw = nameOfID;
						String IDName = getValueRep(IDNameraw);
						// String index = theCode;
						int arraySize = -1;
						String arrayType = "int";
						if (IDName.equals("@" + IDNameraw)) {
							// global.
							for (int ti = 0; ti < SL_Global.size(); ti++) {
								if (SL_Global.get(ti).name.equals(IDNameraw)) {
									// found!
									arraySize = SL_Global.get(ti).arrayIndex;
									arrayType = SL_Global.get(ti).type;
									break;
								}
							}
							// error("array definition not found!");
						} else {
							// inFunc.
							for (int ti = 0; ti < SL_inFunc.size(); ti++) {
								if (SL_inFunc.get(ti).name.equals(IDNameraw)) {
									// found!
									arraySize = SL_inFunc.get(ti).arrayIndex;
									arrayType = SL_inFunc.get(ti).type;
									break;
								}
							}
							if (arraySize == -1) {
								for (int ti = 0; ti < SL_Global.size(); ti++) {
									if (SL_Global.get(ti).name
											.equals(IDNameraw)) {
										// found!
										arraySize = SL_Global.get(ti).arrayIndex;
										arrayType = SL_Global.get(ti).type;
										break;
									}
								}
							}
							// error("array definition not found!");
						}
						String tmp3 = getTmpVal();
						result += tmp3
								+ " = "
								+ _getelementptr(IDName, arraySize, arrayType,
										tmp2) + "\n";

						String resultVar = values.pop();
						result += _store(resultVar, tmp3,
								currentTypeInExpression);
						deal = true;
						break;
					}
					if (theType.equals("natural")) {
						// constant index
						String tmp3 = getTmpVal();
						// String theTmp = getTmpVal();
						String IDNameraw = nameOfID;
						String IDName = getValueRep(IDNameraw);
						String index = theCode;
						int arraySize = -1;
						String arrayType = "int";
						if (IDName.equals("@" + IDNameraw)) {
							// global.
							for (int ti = 0; ti < SL_Global.size(); ti++) {
								if (SL_Global.get(ti).name.equals(IDNameraw)) {
									// found!
									arraySize = SL_Global.get(ti).arrayIndex;
									arrayType = SL_Global.get(ti).type;
									break;
								}
							}
							// error("array definition not found!");
						} else {
							// inFunc.
							for (int ti = 0; ti < SL_inFunc.size(); ti++) {
								if (SL_inFunc.get(ti).name.equals(IDNameraw)) {
									// found!
									arraySize = SL_inFunc.get(ti).arrayIndex;
									arrayType = SL_inFunc.get(ti).type;
									break;
								}
							}
							if (arraySize == -1) {
								for (int ti = 0; ti < SL_Global.size(); ti++) {
									if (SL_Global.get(ti).name
											.equals(IDNameraw)) {
										// found!
										arraySize = SL_Global.get(ti).arrayIndex;
										arrayType = SL_Global.get(ti).type;
										break;
									}
								}
							}
							// error("array definition not found!");
						}

						result += tmp3
								+ " = "
								+ _getelementptr(IDName, arraySize, arrayType,
										index) + "\n";
						// result += _load(tmp3,theTmp,arrayType);
						String resultVar = values.pop();
						result += _store(resultVar, tmp3,
								currentTypeInExpression);
						deal = true;
						break;
					}

				}

				// save the value.
				if (!deal) {
					String resultVar = values.pop();
					result += _store(resultVar, getValueRep(nameOfID),
							currentTypeInExpression);
				}
			}// end exp-deal

		} else if (nodeType.equals("factor")) {
			// first,check what kind of factor it is.
			int naturalLoc = hasChildrenWithType(node, "natural");
			int fractionLoc = hasChildrenWithType(node, "fraction");
			int idLoc = hasChildrenWithType(node, "id");
			if (idLoc >= 0 && naturalLoc >= 0) {
				// an array.
				String tmp3 = getTmpVal();
				String theTmp = getTmpVal();
				String IDNameraw = getCode(node.getChildAt(idLoc).toString());
				String IDName = getValueRep(IDNameraw);
				String index = getCode(node.getChildAt(naturalLoc).toString());
				int arraySize = -1;
				String arrayType = "int";
				if (IDName.equals("@" + IDNameraw)) {
					// global.
					for (int i = 0; i < SL_Global.size(); i++) {
						if (SL_Global.get(i).name.equals(IDNameraw)) {
							// found!
							arraySize = SL_Global.get(i).arrayIndex;
							arrayType = SL_Global.get(i).type;
							break;
						}
					}
					// error("array definition not found!");
				} else {
					// inFunc.
					for (int i = 0; i < SL_inFunc.size(); i++) {
						if (SL_inFunc.get(i).name.equals(IDNameraw)) {
							// found!
							arraySize = SL_inFunc.get(i).arrayIndex;
							arrayType = SL_inFunc.get(i).type;
							break;
						}
					}
					if (arraySize == -1) {
						for (int i = 0; i < SL_Global.size(); i++) {
							if (SL_Global.get(i).name.equals(IDNameraw)) {
								// found!
								arraySize = SL_Global.get(i).arrayIndex;
								arrayType = SL_Global.get(i).type;
								break;
							}
						}
					}
					// error("array definition not found!");
				}

				result += tmp3 + " = "
						+ _getelementptr(IDName, arraySize, arrayType, index)
						+ "\n";
				result += _load(tmp3, theTmp, arrayType);

				// result += _load(,theTmp,arrayType);
				values.push(theTmp);
			} else if (idLoc >= 0) {
				// check if it's 2 ids.
				boolean deal = false;
				for (int nextIDLoc = idLoc + 1; nextIDLoc < node
						.getChildCount(); nextIDLoc++) {
					if (getType(node.getChildAt(nextIDLoc).toString()).equals(
							"id")) {
						String nextIDCode = getCode(node.getChildAt(nextIDLoc)
								.toString());
						// start operation
						String tmp1 = getTmpVal();
						result += _load(getValueRep(nextIDCode), tmp1, "int");
						String tmp2 = getTmpVal();
						result += tmp2 + " = sext i32 " + tmp1 + " to i64\n";
						// String theTmp = getTmpVal();
						String IDNameraw = getCode(node.getChildAt(idLoc)
								.toString());
						String IDName = getValueRep(IDNameraw);
						String index = getCode(node.getChildAt(nextIDLoc)
								.toString());
						int arraySize = -1;
						String arrayType = "int";
						if (IDName.equals("@" + IDNameraw)) {
							// global.
							for (int i = 0; i < SL_Global.size(); i++) {
								if (SL_Global.get(i).name.equals(IDNameraw)) {
									// found!
									arraySize = SL_Global.get(i).arrayIndex;
									arrayType = SL_Global.get(i).type;
									break;
								}
							}
							// error("array definition not found!");
						} else {
							// inFunc.
							for (int i = 0; i < SL_inFunc.size(); i++) {
								if (SL_inFunc.get(i).name.equals(IDNameraw)) {
									// found!
									arraySize = SL_inFunc.get(i).arrayIndex;
									arrayType = SL_inFunc.get(i).type;
									break;
								}
							}
							if (arraySize == -1) {
								for (int i = 0; i < SL_Global.size(); i++) {
									if (SL_Global.get(i).name.equals(IDNameraw)) {
										// found!
										arraySize = SL_Global.get(i).arrayIndex;
										arrayType = SL_Global.get(i).type;
										break;
									}
								}
							}
							// error("array definition not found!");
						}
						String tmp3 = getTmpVal();
						result += tmp3
								+ " = "
								+ _getelementptr(IDName, arraySize, arrayType,
										tmp2) + "\n";
						String tmp4 = getTmpVal();
						result += _load(tmp3, tmp4, arrayType);
						values.push(tmp4);

						// ends
						deal = true;
						break;
					}
				}

				if (!deal) {
					String theTmp = getTmpVal();
					String IDNameraw = getCode(node.getChildAt(idLoc)
							.toString());
					String IDName = getValueRep(IDNameraw);
					result += _load(IDName, theTmp, currentTypeInExpression);
					values.push(theTmp);
				}
				// end

				// a variable reference.
			} else if (naturalLoc >= 0) {
				values.push(getCode(node.getChildAt(naturalLoc).toString()));
				// a natural number.
			} else if (fractionLoc >= 0) {
				// a fraction number.
			} else // there's thing below.
			{
				for (int i = 0; i < node.getChildCount(); i++)
					codeGen((DefaultMutableTreeNode) node.getChildAt(i));
			}
		} else if (nodeType.equals("expression") || nodeType.equals("term")) {
			// first, treat sons
			for (int i = 0; i < node.getChildCount(); i++)
				codeGen((DefaultMutableTreeNode) node.getChildAt(i));
			// if there are only one son, skip next ops!
			if (node.getChildCount() > 1) {
				// now assume that every valuable is generated.
				String resultTmp = getTmpVal();
				String OA1 = values.pop();
				String OA2 = values.pop();
				String OP = ops.pop();
				String codeResult = _op(resultTmp, OP, OA1, OA2,
						currentTypeInExpression);
				result += codeResult;
				values.push(resultTmp);
			}

		} else if (nodeType.equals("condition")) {
			codeGenCondition(node);
		} else if (nodeType.equals("loop")) {
			codeGenLoop(node);
		} else if (nodeType.equals("plus")) {
			ops.push("+");
		} else if (nodeType.equals("minus")) {
			ops.push("-");
		} else if (nodeType.equals("star")) {
			ops.push("*");
		} else if (nodeType.equals("slash")) {
			ops.push("/");
		} else {
			// do nothing and continue.
			for (int i = 0; i < node.getChildCount(); i++)
				codeGen((DefaultMutableTreeNode) node.getChildAt(i));
		}
	}

	private void codeGenAssignWithFunc(DefaultMutableTreeNode node) {
		String tmpVal1Name = getCode(node.getChildAt(0).toString());
		String tmpVal1 = getValueRep(tmpVal1Name);
		if (node.getChildCount() == 3) {
			codeGen((DefaultMutableTreeNode) node.getChildAt(2));
		} else {
			codeGen((DefaultMutableTreeNode) node.getChildAt(0).getChildAt(1));
		}
		result += _store(functionReturn, tmpVal1, "int");
	}

	private void codeGenLoop(DefaultMutableTreeNode node) {
		codeGen((DefaultMutableTreeNode) node.getChildAt(3));
		codeGen((DefaultMutableTreeNode) node.getChildAt(5));
		String tmpVal2 = values.pop();
		String tmpVal1 = values.pop();
		String tmpVal3 = getTmpVal();
		String tmpVal4 = getTmpVal();
		String tmpVal5 = getTmpVal();
		String tmpVal6 = getTmpVal();
		String branch1 = getBranchNum();
		String branch2 = getBranchNum();
		String branch3 = getBranchNum();
		String counterID = getCode(node.getChildAt(1).toString());
		result += _store(tmpVal1, getValueRep(counterID), "int");
		result += ("br label " + branch1 + "\n");
		result += "\n";
		result += ("; <label>:" + branch1.substring(1) + "\n");
		result += _load(getValueRep(counterID), tmpVal6, "int");
		result += (tmpVal3 + " = icmp sle i32 " + tmpVal6 + ", " + tmpVal2 + "\n");
		result += ("br i1 " + tmpVal3 + ", label " + branch2 + ", label "
				+ branch3 + "\n");
		result += "\n";
		result += ("; <label>:" + branch2.substring(1) + "\n");
		codeGen((DefaultMutableTreeNode) node.getChildAt(7));
		result += _load(getValueRep(counterID), tmpVal4, "int");
		result += _op(tmpVal5, "+", tmpVal4, "1", "int");
		result += _store(tmpVal5, getValueRep(counterID), "int");
		result += ("br label " + branch1 + "\n");
		result += "\n";
		result += ("; <label>:" + branch3.substring(1) + "\n");
	}

	private void codeGenCondition(DefaultMutableTreeNode node) {
		codeGenConditionFirst((DefaultMutableTreeNode) node.getChildAt(0));
	}

	private void codeGenConditionFirst(DefaultMutableTreeNode node) {
		if (hasChildrenWithType(node, "comparison") != -1) {
			String branch1 = getBranchNum();
			String branch2 = getBranchNum();
			String tmpVal1 = getTmpVal();
			String relation = node.getChildAt(1).getChildAt(0).getChildAt(1)
					.toString();
			relation = getCode(relation);
			codeGen((DefaultMutableTreeNode) node.getChildAt(1).getChildAt(0)
					.getChildAt(0));
			codeGen((DefaultMutableTreeNode) node.getChildAt(1).getChildAt(0)
					.getChildAt(2));
			String compareRight = values.pop();
			String compareLeft = values.pop();
			result += (tmpVal1 + " = " + opInLLVM(relation, true) + " i32 "
					+ compareLeft + ", " + compareRight + "\n");
			result += ("br i1 " + tmpVal1 + ", label " + branch1 + ", label "
					+ branch2 + "\n");
			result += "\n";
			result += ("; <label>:" + branch1.substring(1) + "\n");
			codeGen((DefaultMutableTreeNode) node.getChildAt(2));
			result += ("br label " + branch2 + "\n");
			result += ("; <label>:" + branch2.substring(1) + "\n");
		} else {
			String branch1 = getBranchNum();
			String branch2 = getBranchNum();
			String tmpVal1 = getTmpVal();
			String relation = node.getChildAt(0).getChildAt(0).getChildAt(0)
					.getChildAt(1).toString();
			relation = getCode(relation);
			codeGen((DefaultMutableTreeNode) node.getChildAt(0).getChildAt(0)
					.getChildAt(0).getChildAt(0));
			codeGen((DefaultMutableTreeNode) node.getChildAt(0).getChildAt(0)
					.getChildAt(0).getChildAt(2));
			String compareRight = values.pop();
			String compareLeft = values.pop();
			result += (tmpVal1 + " = " + opInLLVM(relation, true) + " i32 "
					+ compareLeft + ", " + compareRight + "\n");
			result += ("br i1 " + tmpVal1 + ", label " + branch1 + ", label "
					+ branch2 + "\n");
			result += "\n";
			result += ("; <label>:" + branch1.substring(1) + "\n");
			codeGen((DefaultMutableTreeNode) node.getChildAt(0).getChildAt(1));
			result += ("br label " + branch2 + "\n");
			result += ("; <label>:" + branch2.substring(1) + "\n");
		}
	}

	void error(String why) {
		JOptionPane.showMessageDialog(null, why, "IR Generation Error",
				JOptionPane.INFORMATION_MESSAGE);
		int a = 1;
		// a = a / 0;

	}

	// generate some code stub.
	String typeInLLVM(String t) {
		if (t.equals("int"))
			return "i32";
		if (t.equals("real"))
			return "float";
		error("Invalid Type in typeInLLVM" + t);
		return "[unknown:" + t + "]";
	}

	String opInLLVM(String op, boolean isInt) {
		if (op.equals("+"))
			return "add";
		if (op.equals("-"))
			return "sub";
		if (op.equals("*"))
			return "mul";
		if (isInt) {
			if (op.equals("/"))
				return "sdiv";
			if (op.equals("=="))
				return "icmp eq";
			if (op.equals("!="))
				return "icmp ne";
			if (op.equals("<"))
				return "icmp slt";
			if (op.equals(">"))
				return "icmp sgt";
			if (op.equals("<="))
				return "icmp sle";
			if (op.equals(">="))
				return "icmp sge";
		} else {
			if (op.equals("/"))
				return "fdiv";
			if (op.equals("=="))
				return "fcmp eq";
			if (op.equals("!="))
				return "fcmp ne";
			if (op.equals("<"))
				return "fcmp olt";
			if (op.equals(">"))
				return "fcmp ogt";
			if (op.equals("<="))
				return "fcmp ole";
			if (op.equals(">="))
				return "fcmp oge";
		}
		error("Failed to get IR presentation on OP " + op);
		return "";
	}

	String _alloca(String target, String type) {
		return target + " = alloca " + typeInLLVM(type) + ", align 4\n";
	}

	String _alloca(String target, String type, int size) {
		return target + " = alloca [" + size + " x " + typeInLLVM(type)
				+ "], align 16\n";
	}

	String _global(String target, String type) {
		return "@" + target + " = global " + typeInLLVM(type) + " 0, align 4\n";
	}

	String _global(String target, String type, int size) {
		return "@" + target + " = global [" + size + " x " + typeInLLVM(type)
				+ "] zeroinitializer, align 16\n";
	}

	String _store(String from, String to, String type) {
		return "store " + typeInLLVM(type) + " " + from + " , "
				+ typeInLLVM(type) + "* " + to + " ,align 4\n";
	}

	String _load(String from, String to, String type) {
		return to + " = load " + typeInLLVM(type) + "* " + from + ", align 4\n";
	}

	/*
	 * String _getPtr(String from,String to,int size,String type,String index) {
	 * return to +
	 * " = getelementptr inbounds ["+size+" x "+typeInLLVM(type)+"]* "
	 * +from+" , i32 0, i64 "+index; }
	 */

	String _getelementptr(String from, int size, String type, String index) {
		return "getelementptr inbounds [" + size + " x " + typeInLLVM(type)
				+ "]* " + from + " , i32 0, i64 " + index + "";
	}

	String _op(String result, String op, String oa1, String oa2, String type) {
		boolean isInt;
		isInt = (type == "int");
		return result + " = " + opInLLVM(op, isInt) + " " + typeInLLVM(type)
				+ " " + oa1 + " , " + oa2 + "\n";
	}

	/*
	 * public static void main(String args[]) { AssemblyGenerator ag = new
	 * AssemblyGenerator();
	 * 
	 * }
	 */
}
